package helipay.api.jedis;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Tuple;

/**
 * Redis操作接口
 * 
 */
@Component
@Scope("singleton")
public class RedisAPI {

	private Log logger = LogFactory.getLog(RedisAPI.class);

	@Value("${redis.maxActive}")
	private String maxActive;
	@Value("${redis.maxIdle}")
	private String maxIdle;
	@Value("${redis.maxWait}")
	private String maxWait;
	@Value("${redis.testOnBorrow}")
	private String testOnBorrow;

	@Value("${redis.host}")
	private String host;
	@Value("${redis.port}")
	private String port;

	private JedisPool pool = null;

	public enum Db {
		DEFAULT(0), // 默认数据库
		ONE(1),
		TWO(2),
		THREE(3),
		FOUR(4),
		FIVE(5),
		SIX(6),
		SEVEN(7),
		EIGHT(8);
		
		private int db;

		private Db(int db) {
			this.db = db;
		}

		public int toIntValue() {
			return this.db;
		}

		public Db toDb(int db) {
			if (DEFAULT.db == db) {
				return Db.DEFAULT;
			} else {
				throw new RuntimeException("未知类型[" + db + "].");
			}
		}
	}

	@PostConstruct
	public void init() {
		logger.info("init");

		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxActive(Integer.valueOf(maxActive));
		config.setMaxIdle(Integer.valueOf(maxIdle));
		config.setMaxWait(Integer.valueOf(maxWait));
		config.setTestOnBorrow(Boolean.valueOf(testOnBorrow));

		pool = new JedisPool(config, host, Integer.valueOf(port));
	}

	@PreDestroy
	public void destroy() {
		logger.info("destroy");

		pool.destroy();
	}

	/**
	 * 构建redis连接池
	 * 
	 * @return JedisPool
	 */
	public JedisPool getPool(String key) {
		// int idx = key.hashCode() % 4;
		return pool;
	}

	/**
	 * 返还到连接池
	 * 
	 * @param pool
	 * @param redis
	 */
	public void returnResource(JedisPool pool, Jedis redis) {
		if (pool != null) {
			if (redis != null) {
				redis.select(Db.DEFAULT.db);
				pool.returnResource(redis);
			}
		}
	}

	public void returnBrokenResource(JedisPool pool, Jedis redis) {
		if (pool != null) {
			pool.returnBrokenResource(redis);
		}
	}

	public boolean del(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.del(key) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public String get(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.get(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public boolean set(int db, String key, String value) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			jedis.set(key, value);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public String lpop(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.lpop(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public boolean rpush(int db, String key, String... values) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.rpush(key, values) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return false;
	}

	public boolean lpush(Db db, String key, String... values) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.lpush(key, values) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return false;
	}

	public List<String> lrange(int db, String key, long start, long end) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.lrange(key, start, end);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public String ltrim(int db, String key, long start, long end) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.ltrim(key, start, end);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}
	
	public boolean lrem(int db, String key, long count, String value) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.lrem(key, count, value) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}

	public long llen(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;
		long len = 0;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			len = jedis.llen(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return len;
	}

	public boolean expire(int db, String key, int seconds) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.expire(key, seconds) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}

	public boolean srem(int db, String key, String... values) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.srem(key, values) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public boolean sadd(int db, String key, String... members) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			jedis.sadd(key, members);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public Set<String> smembers(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.smembers(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return null;
	}


	public boolean sismember(int db, String key, String member) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.sismember(key, member);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return false;
	}

	public boolean hset(int db, String key, String field, String value) {

		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			jedis.hset(key, field, value);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public boolean hmset(int db, String key, Map<String, String> hash) {

		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			jedis.hmset(key, hash);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public int ttl(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;
		int result = 0;
		
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			result = jedis.ttl(key).intValue();

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return result;
	}

	public String hget(int db, String key, String field) {

		JedisPool pool = null;
		Jedis jedis = null;

		String value = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			value = jedis.hget(key, field);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return value;
	}

	public boolean hexists(int db, String key, String field) {

		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.hexists(key, field);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return false;
	}

	public Map<String, String> hgetAll(int db, String key) {

		JedisPool pool = null;
		Jedis jedis = null;

		Map<String, String> hash = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			hash = jedis.hgetAll(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return hash;
	}

	public boolean hdel(int db,String key, String... field) {
		JedisPool pool = null;
		Jedis jedis = null;

		long value = 0;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			value = jedis.hdel(key, field);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return (value > 0);
	}

	public List<String> hvals(int db, String key) {
		JedisPool pool = null;
		Jedis jedis = null;
		List<String> result = null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			result = jedis.hvals(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return result;
	}

	public long hincrBy(int db, String key, String field, long value) {
		JedisPool pool = null;
		Jedis jedis = null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);

			return jedis.hincrBy(key, field, value);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return 0;
	}

	/**
	 * 批量insert hash
	 * 
	 * @param key
	 * @param hashDataMap
	 *            k->field , v->value
	 */
	public boolean batchHset(int db, String key, Map<String, String> hashDataMap) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();

			jedis.select(db);

			Pipeline pipeline = jedis.pipelined();

			for (Map.Entry<String, String> data : hashDataMap.entrySet()) {
				pipeline.hset(key, data.getKey(), data.getValue());
			}

			pipeline.sync();

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public class Page {
		private int start;
		private int size;

		public Page(int start, int size) {
			start--;

			if (start < 0) {
				start = 0;
			}

			size = start + size - 1;

			if (size < 0) { // redis 0,0 是取第一个
				start = Integer.MAX_VALUE;
				size = Integer.MAX_VALUE;
			}

			this.start = start;
			this.size = size;
		}

		public int getStart() {
			return start;
		}

		public int getSize() {
			return size;
		}
	}

	/**
	 * 删除模糊匹配的key
	 * @param likeKey 模糊匹配的key
	 * @return 删除成功的条数
	*/
	public long delKeysLike(int db,String likeKey) {
		JedisPool pool = null;
		Jedis jedis = null;
		long i=0;
		try {

			pool = getPool(likeKey);
			jedis = pool.getResource();
			jedis.select(db);
			
			Set<String> keys = jedis.keys(likeKey+"*");
			for (String string : keys) {
				jedis.del(string);
				i++;
			}

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return i;
	}
	
	/**
	 * 查找模糊匹配的key
	 * @param likeKey 模糊匹配的key
	 * @return 删除成功的条数
	*/
	public Set<String> getKeysLike(int db,String likeKey) {
		JedisPool pool = null;
		Jedis jedis = null;
		Set<String> keys=null;
		try {

			pool = getPool(likeKey);
			jedis = pool.getResource();
			jedis.select(db);
			
			keys = jedis.keys(likeKey+"*");
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return keys;
	}

	/**
	 * set hash key 可以有过期时间
	 * @param db
	 * @param key
	 * @param seconds
	 * @param value
	 * @return
	 */
	public boolean setex(int db,String key,int seconds,String value) {
		JedisPool pool = null;
		Jedis jedis = null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			jedis.setex(key, seconds, value);
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}
	
	public boolean exists(int db,String key) {
		JedisPool pool = null;
		Jedis jedis = null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			return jedis.exists(key);
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return false;
	}
	
	public void flushDB(int db) {
		JedisPool pool = null;
		Jedis jedis = null;
		try {

			pool = getPool("");
			jedis = pool.getResource();
			jedis.select(db);
			
			jedis.flushDB();
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
	}
	
	/**
	 * 命令添加指定的成员到key对应的有序集合中，每个成员都有一个分数。你可以指定多个分数/成员组合
	 * @param key,map
	 * @return 
	*/
	public boolean zadd(int db,String key,double f,String member) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			jedis.zadd(key,f,member);
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}
	
	/**
	 * 为有序集key的成员member的score值加上增量increment。如果key中不存在member，就在key中添加一个member，
	 * @param key ,score,member
	 * @return
	*/
	public boolean zincrby(int db,String key,Double score,String member) {
		JedisPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			jedis.zincrby(key, score, member);
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}
	
	/**
	 * 获得成员按score值递减(从大到小)排列的排名。
	 * @param key ,score,member
	 * @return 排名
	*/
	public long zrevrank(int db,String key,String member) {
		JedisPool pool = null;
		Jedis jedis = null;
		long a=0l;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			a=jedis.zrevrank(key, member);
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return a;
	}
	
	/**
	 * 返回key的有序集元素个数
	 * @param key ,score,member
	 * @return 排名
	*/
	public long zcard(int db,String key) {
		JedisPool pool = null;
		Jedis jedis = null;
		long a=0l;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			a=jedis.zcard(key);
		

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return a;
	}
	
	/**
	 * 返回在排序的设置返回的成员范围，通过索引，下令从分数高到低 .包含分数和member
	 * @param key ,score,member
	 * @return 排名 getScore getElment;
	*/
	public Set<Tuple> zrevrangeWithScores(int db,String key,long start,long end) {
		JedisPool pool = null;
		Jedis jedis = null;
		Set<Tuple> a=null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			a=jedis.zrevrangeWithScores(key, start, end);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return a;
	}
	
	/**
	 * member获取成员在排序设置相关的比分
	 * @param key ,score,member
	 * @return 排名 getScore getElment;
	*/
	public double zscore(int db,String key,String member) {
		JedisPool pool = null;
		Jedis jedis = null;
		double a=0d;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db);
			
			a=jedis.zscore(key,member);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return a;
	}

	public Page getPage(int mysqlStart, int mysqlSize) {
		return new Page(mysqlStart, mysqlSize);
	}
	
	public boolean jobSentinel(int db,String lockKey,int expireTime){
		JedisPool pool = null;
		Jedis jedis = null;
		boolean lock=false;
		try {

			pool = getPool(lockKey);
			jedis = pool.getResource();
			jedis.select(db);
			Long status=jedis.setnx(lockKey,lockKey);
			jedis.expire(lockKey,expireTime);
			return status!=null?status>0:lock;
		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return lock;
	}
	public static void main(String[] args) {
		Page p = new RedisAPI().getPage(0, 1);
		System.out.println(p.getStart() + "," + p.getSize());

		// Map<String, String> hashDataMap = new HashMap<String, String>();
		// hashDataMap.put("1", "yechong");
		// hashDataMap.put("2", "carlye");
		//
		// RedisAPI.batchHset("keewee-test", hashDataMap);
	}
}
